#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#define MAX_SIZE 8
typedef union semun // 定义信号量控制结构体
{
  int value;
  struct semid_ds *buf;
  unsigned short *array;
} semuns;

void ops_init(struct sembuf *ops)
{
  ops[0].sem_num = 0; // 信号量编号,从0开始
  ops[0].sem_op = -1;
  ops[0].sem_flg = SEM_UNDO; // 设置信号量操作undo

  ops[1].sem_num = 1;
  ops[1].sem_op = -1;
  ops[1].sem_flg = SEM_UNDO;

  ops[2].sem_num = 2;
  ops[2].sem_op = -1;
  ops[2].sem_flg = SEM_UNDO;

  ops[3].sem_num = 0;
  ops[3].sem_op = 1;
  ops[3].sem_flg = SEM_UNDO;

  ops[4].sem_num = 1;
  ops[4].sem_op = 1;
  ops[4].sem_flg = SEM_UNDO;

  ops[5].sem_num = 2;
  ops[5].sem_op = 1;
  ops[5].sem_flg = SEM_UNDO;
}

int main()
{
  // 第一个信号量是lock,第二个是产品数量,第三个是仓库大小
  key_t key_1, key_2;
  int semid, shmid;
  struct sembuf ops[6];
  char *ptr, *temp;
  int count = 0;
  char buf[128];

  key_1 = ftok("/", 'a');
  key_2 = ftok("/", 'b');
  semid = semget(key_1, 3, 0666 | IPC_CREAT);    // 创建3个信号量
  shmid = shmget(key_2, 1024, 0666 | IPC_CREAT); // 创建共享内存
  ptr = shmat(shmid, 0, 0);                      // 将共享内存连接到当前进程的地址空间
  if (semid < 0 || shmid < 0)
  {
    perror("Error in semget or shmget");
    exit(1);
  }
  // 给信号量赋初值
  // semuns arg;
  // unsigned short arr[3] = {1, 0, MAX_SIZE};
  // arg.array = arr;
  // semctl(semid, 0, SETALL, arg); // 设置信号量初值,从0开始依次设置
  // printf("信号量初始化成功\n");
  // 给ops赋值
  ops_init(ops);
  printf("开始运行\n");

  temp = ptr;

  while (1)
  {
    // 模拟消费者
    // 先获取产品
    semop(semid, &ops[1], 1);
    // 再获取锁
    semop(semid, &ops[0], 1);
    // 消费产品
    strncpy(buf, temp, 128);
    printf("消费者消费了%s\n", buf);
    // 清空缓冲区
    memset(temp, 0, 128);
    temp += 128;
    if (temp >= ptr + 1024)
    {
      temp = ptr;
    }
    // 释放锁
    semop(semid, &ops[3], 1);
    // 仓库空间加1
    semop(semid, &ops[5], 1);
    if (strcmp(buf, "exit\n") == 0)
    {
      printf("消费者退出\n");
      exit(0);
    }
    // 清空buf
    memset(buf, 0, 128);
  }
  exit(0);
}